#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : user_route.py
@TIME          : 2025/03/02 10:00:00
@AUTHOR        : chenlip
@VERSION       : 0.1.0
@DESCRIPTION   : 用户路由视图，包括用户注册、登录等功能
'''

import datetime
import random
import time

from flask import Blueprint, g, request, render_template, redirect, url_for, flash, session, abort
from flask import current_app, jsonify

from flask_login import login_user, logout_user, login_required, current_user
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_required, get_jwt_identity

from app.common.logutil import log, log_error, log_info

from app.service.user_service import UserService
from app.service.avatar_service import AvatarService  # 导入头像服务
from app.service.validate_data import ValidateData
from app.service.sse_notifi import NotificationService # 导入通知服务

from app.middlewares.error_handler import route_exceptions, BusinessError
from app.middlewares.rate_limit_decorator import ip_rate_limiter, file_manager, get_request_identifier, rate_limit

# 创建用户蓝图
user_bp = Blueprint('user', __name__, url_prefix='/user')

@user_bp.route('/admin', methods=['GET', 'POST'])
@login_required
@route_exceptions
def admin():
    """用户管理页面"""
    if not current_user.is_admin:
        raise BusinessError('您不是管理员，没有权限访问该页面')
    
    return render_template('baseadmin.html', user_data=current_user)

@user_bp.route('/register', methods=['GET', 'POST']) 
@rate_limit(type='register')
@route_exceptions
def register():
    """
    用户注册路由
    
    GET: 返回注册页面
    POST: 处理注册表单提交
    """
    # 若当前已登录,且为生产环境，直接跳转到管理页面
    if current_user.is_authenticated and current_app.config.get('is_prod'):
        return redirect(url_for('bbs.bbsindex'))
    
    # 处理GET请求
    if request.method == 'GET':
        return render_template('userreg.html')
    
    # 获取已清洗的表单数据
    form_data = ValidateData.get_sanitized_form(request)

    # 表单数据验证
    v_result = ValidateData.validate_register_data(form_data)
    if not v_result['success']:
        # 改为抛出业务错误，由装饰器统一处理
        raise BusinessError(v_result)
    
    # 准备注册数据
    register_data = {
        'loginname': form_data.get('loginname'),
        'nickname': form_data.get('nickname'),
        'password': form_data.get('password'),
        'email': form_data.get('email'),
        'phone': form_data.get('phone', '')
    }
    
    # 调用用户服务进行注册
    result = UserService.register(register_data)
    
    if result['success']:
        flash('注册成功，请登录', 'success') # 将在登录页面显示
        return redirect(url_for('user.login'))
    else:
        # 改为抛出业务错误，由装饰器统一处理
        raise BusinessError(result['message'], code=result['code'])

@user_bp.route('/login', methods=['GET', 'POST'])
@rate_limit(type='login')
@route_exceptions
def login():
    """用户登录路由"""
    # 若当前已登录，直接跳转到管理页面
    if current_user.is_authenticated and current_app.config.get('is_prod'):
        return redirect(url_for('bbs.bbsindex'))
    
    # 处理GET请求
    if request.method == 'GET':
        return render_template('login.html')
    
    # 获取已清洗的表单数据，清洗工作在before_request中完成
    form_data = ValidateData.get_sanitized_form(request)
    
    # 准备登录数据
    login_data = {
        'login_id': form_data.get('login_id'),
        'password': form_data.get('password'),
        'remember_me': form_data.get('remember_me') == 'on',
    }
    
    # 调用用户登录服务进行登录, 返回登录结果(result)和用户对象(user)
    result_t = UserService.login(login_data)

    if isinstance(result_t, tuple):
        result, user = result_t
    else:
        result = result_t
        user = None
    
    if result['success']:
        
        # 获取用户数据
        user_id = user.user_id

        # 6. 使用Flask-Login管理会话(仅网页会话需要)
        if login_data.get("remember_me", False):
            login_user(user, remember=True) # 记住我
        else:
            login_user(user)

        # 7. 生成JWT令牌(API访问使用)
        access_token = create_access_token(identity=user_id)
        refresh_token = create_refresh_token(identity=user_id)
        
        # # 更新返回结果，添加令牌
        result['data']['access_token'] = access_token
        result['data']['refresh_token'] = refresh_token
        result['data']['token_type'] = 'bearer'

        log.debug(f"---- 用户 {user.loginname} 登录成功 ------")

        if user.is_admin:
            return render_template('admin/baseadmin.html', user_data=result) 
        else:
            return render_template('login.html', user_data=result) 
    
    else:
        _mess = result['message']
            
        flash(_mess, 'error')
        return render_template('login.html')


@user_bp.route('/logout')
@login_required
@route_exceptions
def logout():
    """用户登出路由"""
    
    # 登出用户
    logout_user()

    response = redirect(url_for('user.login'))
    # 必须明确删除关联的Cookie
    response.delete_cookie('session')
    response.delete_cookie('remember_token')
    response.delete_cookie('yourong_bbs_remember_token')
    response.delete_cookie('yourong_bbs_session')

    return response

@user_bp.route('/testsse', methods=['GET'])
@login_required
@route_exceptions
def testsse():
    """测试SSE通知"""
    # 通知测试
    NotificationService.send_user_sse(current_user.user_id, {'message': '这是一条测试通知'})

    return jsonify({
        'success': True,
        'message': '测试通知发送成功'
    })

@user_bp.route('/check-session', methods=['GET'])
def check_session():
    """检查当前会话状态的API端点"""
    if current_user.is_authenticated:
        return jsonify({
            'authenticated': True,
            'user_id': current_user.user_id,
            'timestamp': datetime.datetime.now().isoformat()
        })
    else:
        return jsonify({
            'authenticated': False,
            'timestamp': datetime.datetime.now().isoformat()
        })

@user_bp.route('/token/refresh', methods=['POST'])
@jwt_required(refresh=True)
@route_exceptions
def refresh_token():
    """使用刷新令牌获取新的访问令牌"""
    # 获取当前用户身份
    current_user_id = get_jwt_identity()
    
    # 生成新的访问令牌
    new_access_token = create_access_token(identity=current_user_id)
    
    return jsonify({
        'success': True,
        'message': '令牌刷新成功',
        'access_token': new_access_token,
        'token_type': 'bearer'
    })


@user_bp.route('/human', methods=['GET', 'POST'])
@route_exceptions
def verify_human():
    """人机验证处理 - 用于解除速率限制"""
    # 获取之前的页面URL
    next_url = request.args.get('next') or request.referrer or url_for('main.index')
    
    # 获取请求标识符
    request_id = get_request_identifier()

    # 获取限制状态，用于前端倒计时用
    limit_state = file_manager.get_limit_state(request_id) or {}
    expires_at = limit_state.get('expires_at', time.time() + 60)
    remaining_time = max(0, int(expires_at - time.time()))

    # 从缓存获取验证码
    _s_capthca = session.get('captcha_code')

    if _s_capthca is None and len(limit_state) > 0:
        # 从用户的json文件中获取验证码
        _s_capthca = limit_state.get('captcha_code')
    
    # 处理表单提交
    if request.method == 'POST':
        # 验证码内容
        captcha_response = request.form.get('captcha')

        # 验证逻辑
        if captcha_response == _s_capthca:
            
            # 重置速率限制
            ip_rate_limiter.reset(request_id)
            
            # 显示成功消息
            flash('验证成功，您可以继续浏览', 'success')
            return redirect(next_url)
        else:
            flash('验证失败:您输入的是 {captcha_response}, 服务端保存的是{_s_capthca}，不一致，请重试', 'error')
    
    # 生成新验证码并存储在会话中
    session['captcha_code'] = str(random.randint(1000, 9999))

    # 同步将验证码也写入到json文件中
    if len(limit_state) > 0:
        limit_state['captcha_code'] = session['captcha_code']
        file_manager.save_limit_state(request_id, limit_state)
    
    
    # 准备错误信息
    error_data = {
        'success': False,
        'message': f"请求过于频繁，系统已暂时限制访问。请输入验证码继续访问，或等待 {remaining_time} 秒后自动解除限制。",
        'code': 429,
        'remaining_time': remaining_time
    }
    
    return render_template('errors/rate_error.html', 
                          next_url=next_url, 
                          captcha=session['captcha_code'],
                          error=error_data)




